package org.example.finalobj;

import lombok.extern.slf4j.Slf4j;

import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @author zhengdp
 * @Description 自定义数据库连接池
 * @Date 2022/12/4 15:18
 * @Created by zhengdp
 */
@Slf4j(topic = "c.DataSourcePool")
public class DataSourcePool {

    /**
     * 测试代码
     * @param args
     */
    public static void main(String[] args) {
        DataSourcePool pool = new DataSourcePool(2);
        for(int i =0; i< 5 ; i++) {
            new Thread(() -> {
                Connection conn = pool.borrow();
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                pool.free(conn);
            }).start();
        }
    }

    // 连接池大小 (一般的连接池支持 扩容和收缩）
    private final int poolSize;

    // 连接对象数组
    private Connection[] connections;

    // 连接状态数组 （0:空闲 1:繁忙)
    private AtomicIntegerArray states;

    public DataSourcePool(int poolSize) {
        this.poolSize = poolSize;
        connections = new Connection[poolSize];
        this.states = new AtomicIntegerArray(new int[poolSize]);
        for(int i = 0;i < poolSize;i++){
            connections[i] = new MockConnection("连接" + (i + 1));
        }
    }

    /**
     * 获取连接对象
     * @return
     */
    public Connection borrow() {
        while(true) {
            // 1. 判断空闲连接数组
            for(int i = 0 ; i< poolSize;i ++) {
                if ( states.get(i) == 0 ) {
                    // 2. 重新设置连接数组状态
                    if(states.compareAndSet(i,0,1)){
                        log.info("borrow {}",connections[i]);
                        return connections[i];
                    }
                }
            }
            // 3. 如果没有空闲连接，当前线程进入等待 (何时被唤醒？ ==> 连接被归还时唤醒)
            synchronized (this) {
                try {
                    log.info("wait ....");
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }


    }

    /**
     * 归还连接对象
     * @param connection
     */
    public void free(Connection connection) {
        for(int i =0; i< poolSize ; i ++) {
            if(connections[i] == connection) {
                // 设置连接状态
                states.set(i,0);
                // 唤醒等待线程
                synchronized (this) {
                    log.info("free {}",connection);
                    this.notifyAll();
                }
                break;
            }
        }
    }
}


